/* HMAC-SHA256: Keyed-Hashing for Message Authentication
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 */


#include "hmacsha256.h"
#include <string.h>


void HmacSha256Init(struct HmacSha256Context *ctx, const void *key, unsigned int len)
{
	// init key (64-byte)
	if (len>64) {
		// set sha256(key) as key
		SHA256Init(&ctx->hash);
		SHA256Update(&ctx->hash, key, len);
		SHA256Final(ctx->key, &ctx->hash);
		len = 16;
	} else memcpy(ctx->key, key, len);
	if (len<64) {
		// fill zero padding key
		memset(ctx->key+len, 0, 64-len);
	}

	// set key ^ ipad (0x36) as istr
	uint32_t *istr = (uint32_t*)ctx->key;
	for(; istr<(uint32_t*)(ctx->key+64); ++istr)
		*istr = *istr ^ 0x36363636;
	// update sha256(istr)
	SHA256Init(&ctx->hash);
	SHA256Update(&ctx->hash, ctx->key, 64);
}

inline void HmacSha256Update(struct HmacSha256Context *ctx, const void *data, unsigned int len)
{
	// update sha256(istr)
	SHA256Update(&ctx->hash, data, len);
}

void HmacSha256Final(unsigned char digest[32], struct HmacSha256Context *ctx)
{
	// final sha256(istr)
	SHA256Final(digest, &ctx->hash);

	// recovery key with 0x36, then set key ^ opad (0x5c) as ostr
	uint32_t *istr = (uint32_t*)ctx->key;
	for(; istr<(uint32_t*)(ctx->key+64); ++istr)
		*istr = *istr ^ 0x36363636 ^ 0x5c5c5c5c;

	// update sha256(ostr)
	SHA256Init(&ctx->hash);
	SHA256Update(&ctx->hash, ctx->key, 64);
	SHA256Update(&ctx->hash, digest, 32);
	SHA256Final(digest, &ctx->hash);
}

/*
 * Transform 32 bytes digest into 64 bytes Hex String.
 */
void HmacSha256HexString(char hex[65], const unsigned char digest[32])
{
	static const char HEX[] = "0123456789abcdef";
	int i = 0;
	for(; i<32; ++i) {
		hex[i*2+0] = HEX[(digest[i]>>4)&0xF];
		hex[i*2+1] = HEX[(digest[i]>>0)&0xF];
	}
	hex[64] = '\0';
}